/* 
 *  Copyright 2012 CodeMagi, Inc.
 * 
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package com.codemagi.servlets.content.thumbnailers;

import com.codemagi.servlets.AppException;
import com.codemagi.servlets.BaseServlet;
import com.codemagi.servlets.content.ThumbnailController;
import com.imagero.reader.FileInfo;
import com.imagero.reader.ImageInfo;
import com.imagero.reader.ImageProducerAdapter;
import com.imagero.reader.ImageReader;
import com.imagero.reader.ReaderFactory;
import com.sun.media.jai.codec.FileSeekableStream;
import java.awt.Dimension;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.image.ColorModel;
import java.awt.image.ImageProducer;
import java.awt.image.renderable.ParameterBlock;
import java.io.File;
import javax.media.jai.*;
import javax.servlet.ServletContext;
import org.apache.log4j.Logger;

public class PSDThumbnailer implements com.codemagi.servlets.content.thumbnailers.IThumbnailer {

    Logger log = Logger.getLogger(this.getClass());

    //GETTERS AND SETTERS ------------------------

    public void setApplication(ServletContext newValue) {
	//no-op
    }

    public void createThumbnail(String sourceFile, String thumbFile, int targetWidth, int targetHeight, boolean doOverlay)
        throws AppException {

	String thumbDir = sourceFile.substring(0, sourceFile.lastIndexOf("/") + 1) + ThumbnailController.THUMBS_DIRECTORY + "/" ;

        log.debug("**** createThumbnail(" + sourceFile + ", " + thumbDir + ", " + thumbFile + ")");

	FileSeekableStream ss = null;

        try {
	    RenderedOp source         = null;
	    ss                        = new FileSeekableStream(sourceFile);
	    ParameterBlock loadParams = new ParameterBlock();
	    loadParams.add(ss);

	    //load psd file and convert to awt image
	    ImageReader reader = ReaderFactory.createReader(sourceFile);
	    
	    Image awtImage = null;
	    
	    if (awtImage == null) {
		log.debug("embedded psd thumbnail null");
		
		int layers = reader.getImageCount();
		ImageProducer ip = reader.getProducer(layers-1);
		
		//This line will save memory, and go a little slower
		//but this will actually speed things up very much in low-ram enviornments
		((ImageProducerAdapter)reader.getProducer(layers-1)).setOptimizeScalingFor(ImageProducerAdapter.OPTIMIZE_SCALING_MEMORY);
		
		awtImage = Toolkit.getDefaultToolkit().createImage(ip);
		
	    } else {
		log.debug("embedded thumbnail ripped from psd successfully!");
	    }
	    
	    //convert to planar image
	    ParameterBlock pb = new ParameterBlock();
	    pb.add(awtImage);
	    PlanarImage im = (PlanarImage)JAI.create("awtImage", pb);
	    
	    //convert planar image to RenderedOp
	    ParameterBlock pb2 = new ParameterBlock();
	    pb2.addSource( im );
	    source = JAI.create("null", pb2);
	    
	    //provide info about source:
	    ThumbnailController.outputImageParams(source);
	    
	    //Perform color and/or alpha channel conversions if needed
	    ColorModel cm = source.getColorModel();  
	    int numChannels  = cm.getNumComponents();
	    int bitsPerPixel = cm.getPixelSize();
	    if (cm.getNumComponents() == 4) {
		//convert cmyk to rgb
		source = ThumbnailController.convertCMYKtoRGB(source);
	    }
	    
	    //scale the image
	    source = ThumbnailController.scaleImage(source, targetWidth, targetHeight);
	    
	    //overlay a 'SAMPLE' watermark if this is not an official download
	    if (doOverlay) {
	    	source = ThumbnailController.overlayWatermark(source, source.getWidth(), source.getHeight());
	    }
	    
	    //convert 16 bit color to 8 bit
	    if ( bitsPerPixel / numChannels == 16 ) {
		source = ThumbnailController.convert16BitTo8Bit(source);
	    }
	    
	    //create the output directory if needed
            java.io.File outDir = new File(thumbDir);
            outDir.mkdirs();
	    
	    com.sun.media.jai.codec.JPEGEncodeParam encodeParam = new com.sun.media.jai.codec.JPEGEncodeParam();
	    encodeParam.setQuality(ThumbnailController.THUMBNAIL_ENCODE_QUALITY);
	    if (!doOverlay) encodeParam.setQuality(ThumbnailController.DOWNLOAD_ENCODE_QUALITY);
	    
	    //save the image to the filesystem
	    log.debug("ABOUT TO CREATE: source: " + source + " thumbFile: " + thumbFile);
	    JAI.create("filestore", source, thumbFile, "jpeg", encodeParam);
	    
        } catch (Exception e) {
            log.debug("", e);
            throw new AppException(ThumbnailController.MSG_THUMBNAIL_ERROR);
        } catch (Throwable t) {
            log.debug("", t);
            throw new AppException(ThumbnailController.MSG_THUMBNAIL_ERROR);

        } finally {
	    BaseServlet.closeStream(ss);

	}
    }

    public Dimension getDimension(String sourceFile) throws AppException {

	try {

	    FileInfo fileInfo = FileInfo.getFileInfo(sourceFile);
	    int imageCount = fileInfo.getImageCount();
	    
	    log.debug("PSDThumbnailer.getDimension() imageCount=" + imageCount);
	    
	    Dimension finalDim = new Dimension(0, 0);
	    
	    for (int i = 0; i < imageCount; i++) {
		try {
		    ImageInfo imageInfo = fileInfo.getImageInfo(i);
		    Rectangle r = imageInfo.getBounds(); //union of bounds of all layers
		    
		    log.debug("image " + i + ":" + r.getWidth());
		    log.debug("image " + i + ":" + r.getHeight());
		    
		    finalDim.setSize( r.getSize());
		    //finalDim = new Dimension( (int)r.getHeight(), (int)r.getWidth() ); //HACK! This is reversed to account for reversed dimensions in Imagero
		} catch (Exception ie) {
		    log.debug("image " + i + " failed");
		} 
	    }
	    
	    return finalDim;

	} catch (Exception ae) {
	    log.debug("error loading psd file for getDimension ", ae);
	    throw new AppException("Error loading file: " + ae.getMessage());

	}
    }

}
